using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using TuringMachine;
using System.IO;

namespace SimulatorGui
{
    public partial class MainForm : Form
    {
        private TuringMachine.Controller _turingMachineController = null;
        private uint currentStep;
        private bool _compiled;
        
        public MainForm()
        {
            InitializeComponent();
            _turingMachineController = new Controller();
            _compiled = false;
            currentStep = 0;
            
        }

        private void aboutToolStripMenuItem_Click(object sender, EventArgs e)
        {
            new AboutBox().ShowDialog();
        }

        private void button8_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        private void button2_Click(object sender, EventArgs e)
        {
            new InputLoad(ref tapeControl1,ref _turingMachineController).ShowDialog(this);
        }

        private void button5_Click(object sender, EventArgs e)
        {
            btnRun.Enabled = true;
            btnPause.Enabled = btnStop.Enabled = false;
           
            timerRun.Stop();
        }

        //
        private void button4_Click(object sender, EventArgs e)
        {
            StopRunning("Stopped by user");
          
            this.moveToStart();
        }

        private void MainForm_Load(object sender, EventArgs e)
        {
            this.tapeControl1.Text = _turingMachineController.GetTapeString();
            this.tapeControl1.CurrentIndex = _turingMachineController.GetTapeIndex();
            this.txtScript.Text = string.Empty;
            this.txtOutput.Text = string.Empty;
            SpeedUpdate();
            if (!_compiled)
            {
                MakeNotCompiled();
            }

            
            System.Reflection.Assembly thisAssembly = this.GetType().Assembly;
            object[] attributes = thisAssembly.GetCustomAttributes(typeof(System.Reflection.AssemblyTitleAttribute),false);
            WriteToOutput("Started {0}{2}Version: {1}{2}", ((System.Reflection.AssemblyTitleAttribute)attributes[0]).Title,
                thisAssembly.GetName().Version.ToString(),Environment.NewLine);
        }

        private void WriteToOutput(string text) 
        {
            StringBuilder toWrite = new StringBuilder(this.txtOutput.Text);
            toWrite.Append(text);
            toWrite.Append(Environment.NewLine);
            this.txtOutput.Text = toWrite.ToString();
            txtOutput.SelectionStart = txtOutput.Text.Length;
            txtOutput.ScrollToCaret();
        }
        private void WriteToOutput(string format, params object[] args) 
        {
            StringBuilder toWrite = new StringBuilder(this.txtOutput.Text);
            toWrite.AppendFormat(format, args);
            toWrite.Append(Environment.NewLine);
            this.txtOutput.Text = toWrite.ToString();
            txtOutput.SelectionStart = txtOutput.Text.Length;
            txtOutput.ScrollToCaret();
        }

        private void button7_Click(object sender, EventArgs e)
        {
            this.txtOutput.Text = string.Empty;
            WriteToOutput("Output window cleaned");
        }

        private void btnCompile_Click(object sender, EventArgs e)
        {
            try
            {
                string script;
                script = txtScript.Text;
                _turingMachineController.Compile(script);
                this.groupRunControl.Enabled = true;
                btnRun.Enabled = true;
                btnPause.Enabled = btnStop.Enabled = false;
                this.txtMaxStep.Enabled = true;
                FormUpdate();
                WriteToOutput("Compilation succeed");
                //WriteToOutput();
            }
            catch (Exception e1)
            {

                MessageBox.Show(e1.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                WriteToOutput("Compilation error: {0}", e1.Message, Environment.NewLine);
            }
        }

        private void txtScript_TextChanged(object sender, EventArgs e)
        {
            _compiled = false;
            MakeNotCompiled();
        }

        private void MakeNotCompiled()
        {
            this.groupRunControl.Enabled = false;
            this.txtMaxStep.Enabled = false;
        }

        private void trackBar1_Scroll(object sender, EventArgs e)
        {
            timerRun.Interval = 1600 - (trackBar1.Value) * 100;
            SpeedUpdate();
        }

        private void btnStep_Click(object sender, EventArgs e)
        {
             MakeStep();
        }

        private bool MakeStep()
        {
            currentStep++;
            try
            {
                WriteToOutput("[" + currentStep + "]:" + _turingMachineController.PerformStep());
            }
            catch (Exception e1)
            {

                StopRunning(e1.Message); 
                return false;
            }
           
            
            FormUpdate();
            
            string reason = string.Empty;
            
            if (IsStop(ref reason))
            {
                StopRunning(reason);
            }
            return true;
        }
        private bool IsStop(ref string reason)
        {
            
           
            bool _ret = _turingMachineController.IsStop(ref reason);
            int maxStep = Int32.Parse(txtMaxStep.Text);
            if (currentStep>=maxStep)
            {
                _ret = true;
                reason = "Reached maximum steps";
            }
            return _ret;
        }

        private void btnRun_Click(object sender, EventArgs e)
        {
            btnRun.Enabled = false;
            btnPause.Enabled = btnStop.Enabled = true;
          
            timerRun.Start();
            
        }

        private void saveToolStripMenuItem_Click(object sender, EventArgs e)
        {
            saveFileDialog1.DefaultExt = ".tms";
            saveFileDialog1.Filter = "Turing Machine Script|*.tms";
            saveFileDialog1.Title = "Save Turing machine script";
            //saveFileDialog1.CheckFileExists = true;
            saveFileDialog1.ShowDialog(this);

            if (saveFileDialog1.FileName!="")
            {
                using (StreamWriter  writer = new StreamWriter (saveFileDialog1.FileName,false))
                {
                    writer.Write(txtScript.Text);
                    writer.Close();

                }
                
            }
            
        }

        private void loadToolStripMenuItem_Click(object sender, EventArgs e)
        {
            openFileDialog1.DefaultExt = ".tms";
            openFileDialog1.Filter = "Turing Machine Script|*.tms";
            openFileDialog1.Title = "Load Turing machine script";
            openFileDialog1.CheckFileExists = true;
            //saveFileDialog1.CheckFileExists = true;
            openFileDialog1.ShowDialog(this);
            StringBuilder _script = new StringBuilder ();
            if (openFileDialog1.FileName != "")
            {
                using (StreamReader reader = new StreamReader(openFileDialog1.FileName))
                {
                    
                    txtScript.Text = reader.ReadToEnd();
                    reader.Close();
                }

            }
        }

        private void timerRun_Tick(object sender, EventArgs e)
        {
            MakeStep();
        }

        private void btnRestart_Click(object sender, EventArgs e)
        {
            this.moveToStart();
            btnPause.Enabled = btnStop.Enabled = btnRun.Enabled = btnStep.Enabled = true;
            currentStep = 0;
            FormUpdate();
        }

        private void moveToStart()
        {
            this._turingMachineController.MoveAutomatToStart();
        }

        private void FormUpdate()
        {
            this.tapeControl1.Text = _turingMachineController.GetTapeString();
            this.tapeControl1.CurrentIndex = _turingMachineController.GetTapeIndex();
            this.txtCurState.Text = _turingMachineController.GetAutomatState();
            this.txtCurStep.Text = this.currentStep.ToString();
            
        }

        private void SpeedUpdate()
        {
            float speed = ((float)timerRun.Interval) / 1000;
            this.txtSpeed.Text = (speed.ToString("N1") + " s.");
        }

        private void StopRunning(string reason)
        {
            timerRun.Stop();
            
            WriteToOutput("Stop running. Reason: " + reason +"\n");
            MessageBox.Show("Stop running\nReason: " + reason, "Stop running", MessageBoxButtons.OK, MessageBoxIcon.Information);                

            //Disable all controls
            btnPause.Enabled = btnStop.Enabled = btnRun.Enabled = btnStep.Enabled = false;
        }


    }
}